package com.gotokeep.gyromousedemo

import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import kotlin.math.PI

class MainActivity : AppCompatActivity() {

    private val sensorListener = SensorListener()
    private val sensorManager: SensorManager by lazy {
        getSystemService(SENSOR_SERVICE) as SensorManager
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initSensor()
        initView()
    }

    override fun onResume() {
        super.onResume()
        initSensor()
    }

    override fun onPause() {
        super.onPause()
        uninitSensor()
    }

    override fun onDestroy() {
        super.onDestroy()
        sensorListener.release()
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        Log.e(TAG, "dispatchTouchEvent->${ev?.x}->${ev?.y}")
        return super.dispatchTouchEvent(ev)
    }

    private fun uninitSensor() {
        sensorManager.unregisterListener(sensorListener)
    }

    private fun initSensor() {
        val sensorList = sensorManager.getSensorList(Sensor.TYPE_GYROSCOPE)
        sensorList?.firstOrNull()?.let { sensor ->
            sensorManager.registerListener(
                sensorListener,
                sensor,
                // 1 ms 分发一次
                SENSOR_MIN_INTERVAL_IN_US
            )
        }
    }

    private fun initView() {
        val root = findViewById<LinearLayout>(R.id.root)
        for (i in 0 until root.childCount) {
            val child = root.getChildAt(i)
            child.setOnClickListener {
                Log.e(TAG, "item -> $i clicked...")
                sensorListener.sendMessage(EventType.TYPE_CLICK)
            }
            child.setOnLongClickListener {
                sensorListener.sendMessage(EventType.TYPE_LONG_CLICK)
                true
            }
        }
    }

    private class SensorListener : SensorEventListener {

        /**
         * 绕 x 轴旋转的弧度
         */
        var deltaXInRad = 0f
            private set

        /**
         * 绕 y 轴旋转的弧度
         */
        var deltaYInRad = 0f
            private set

        /**
         * 绕 z 轴旋转的弧度
         */
        var deltaZInRad = 0f
            private set

        private val dataSender = DataSender(AppContext.SERVER_IP, AppContext.PORT)

        /**
         * 时间戳
         */
        private var timeStamp = 0L

        override fun onSensorChanged(event: SensorEvent?) {
            event ?: return
            if (timeStamp == 0L) {
                this.timeStamp = event.timestamp
                return
            }
            val deltaTimeInUs = event.timestamp - timeStamp
            timeStamp = event.timestamp
            val xDelta = event.values[0] * deltaTimeInUs.toFloat() / (SECOND_IN_US)
            val yDelta = event.values[1] * deltaTimeInUs.toFloat() / (SECOND_IN_US)
            val zDelta = event.values[2] * deltaTimeInUs.toFloat() / (SECOND_IN_US)
            deltaXInRad = handleData(
                oldData = deltaXInRad,
                delta = xDelta,
                lowerBound = -(AppContext.VERTICAL_RAD_RANGE / 2).toFloat(),
                upperBound = (AppContext.VERTICAL_RAD_RANGE / 2).toFloat()
            )
            deltaYInRad = handleData(
                oldData = deltaYInRad,
                delta = yDelta,
                lowerBound = -(AppContext.HORIZONTAL_RAD_RANGE / 2).toFloat(),
                upperBound = (AppContext.HORIZONTAL_RAD_RANGE / 2).toFloat()
            )
            deltaZInRad = handleData(
                oldData = deltaZInRad,
                delta = zDelta,
                lowerBound = -(AppContext.HORIZONTAL_RAD_RANGE / 2).toFloat(),
                upperBound = (AppContext.HORIZONTAL_RAD_RANGE / 2).toFloat()
            )
            sendMessage(EventType.TYPE_MOVE)
        }

        override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) = Unit

        fun sendMessage(eventType: EventType) {
            dataSender.sendMessage(
                eventType,
                floatArrayOf(
                    this.deltaXInRad,
                    this.deltaYInRad,
                    this.deltaZInRad
                )
            )
        }

        fun release() {
            dataSender.release()
        }
    }

    companion object {

        private const val TAG = "MainActivity"

        private const val SECOND_IN_US = 1000_000_000

        /**
         * 传感器数据更新的频率，单位 微秒
         */
        private const val SENSOR_MIN_INTERVAL_IN_US = 1000

        fun handleData(
            oldData: Float,
            delta: Float,
            lowerBound: Float = -PI.toFloat() / 2,
            upperBound: Float = PI.toFloat() / 2
        ): Float {
            val newData = oldData + delta
            return newData.coerceAtMost(upperBound).coerceAtLeast(lowerBound)
        }
    }
}
